import 'dart:async';

import 'package:get/get.dart';
import 'package:shimo_app/bus/struct/error.dart';
import 'package:shimo_app/pages/components/hint.dart';
import 'package:shimo_app/vision/tube_detector.dart';

import '../../services/device_service.dart';
import 'state.dart';
import '../sample_page/sample_controller.dart';

/// 启动组件控制器 - 负责串口连接管理和设备状态监控
class StartComponentController extends GetxController {
  // 依赖注入：获取设备服务实例
  final deviceService = Get.find<DeviceService>();

  // 串口相关状态
  int selectedPortIndex = 0; // 当前选中的串口索引
  List<Map<String, String>> serialPortList = []; // 可用串口列表 [{端口名: 友好名称}]
  late Timer _timer; // 定时器，用于定期更新串口列表
  bool isSerialPortConnected = false; // 串口连接状态
  int busState = -1; // 总线状态 (-2:严重错误, -1:错误, 1:正常)
  List<SetComponentError> errList = []; // 错误信息列表
  Set<int> _previousErrorHashes = {}; // 存储之前错误的哈希值
  // 事件订阅管理
  List<StreamSubscription> _events = [];

  //更多详细信息获取器
  final SampleController _sampleController = SampleController();
  //需要添加详细信息的错误码
  final Set<int> _detailedErrorCodes = {145, 146};
  //错误码表
  final Map<int, String> _errorIdMap = {
    101: "找不到Xhome",
    102: "找不到Yhome",
    103: "找不到Z1 home",
    104: "找不到Z2 home",
    105: "注射泵找不到Home",
    106: "X轴失步 / X轴受阻",
    107: "Y轴失步 / Y轴受阻",
    108: "X轴编码器异常",
    109: "Y轴编码器异常",
    143: "超声波异常",
    144: "多通阀切换错误",
    161: "超过最高温度值",
    162: "超设定温度值"
  };

  @override
  void onInit() {
    // 初始化定时器，每秒更新一次串口列表
    _timer = Timer.periodic(1.seconds, (timer) {
      // 获取设备服务中的串口列表
      final l = deviceService.getPorts();
      bool updated = false; // 标记是否有更新
      List<Map<String, String>> temp = []; // 临时列表用于过滤

      // 过滤串口，只保留包含"SERIAL CH340"的串口（特定硬件设备）
      for (var i in l) {
        if (!i.values.first.contains("SERIAL CH340")) {
          continue; // 跳过不包含指定字符串的串口
        }
        temp.add(i);
      }

      // 注释掉的复杂更新检测逻辑
      // if (l.length == serialPortList.length) {
      // for (var i in serialPortList) {
      //   print(i);
      //   if (l.firstWhereOrNull((element) =>
      //           element.keys.first == i.keys.first &&
      //           element.values.first.contains("CH340")) ==
      //       null) {
      //     updated = true;
      //     break;
      //   }
      // }
      // } else {
      //   updated = true;
      // }
      // if (!updated) return;

      // 更新串口列表并刷新UI
      serialPortList = temp;
      update();
    });

    // 设置总线连接状态监听器
    deviceService.setBusConnectedListener((p0, p1) {
      isSerialPortConnected = p0; // p0: 连接状态
      busState = p1; // p1: 总线状态
      update(); // 状态变化时更新UI
    });

    //错误内容构造
    Future<String> parseErrorStr(SetComponentError err) async {
      //将首部模组信息删除
      // String errMsg = err.content.substring(1);
      String errMsg = err.content;
      StringBuffer ret = StringBuffer();
      int componentId = err.component;
      //特殊错误码更多信息
      switch (componentId) {
        case 141:
          ret.write("${errMsg.substring(0, 1)}号通道，缺液");
          break;
        case 142:
          ret.write("${errMsg.substring(0, 1)}号通道，超声波定容缺液");
          break;
        case 145:
          int index = errMsg.indexOf(" ");
          ret.write("${errMsg.substring(0, index)}号试管，满管");
          break;
        case 146:
          int index = errMsg.indexOf(" ");
          ret.write("${errMsg.substring(0, index)}号试管，空管");
          break;
        default:
          ret.write(_errorIdMap[componentId] ?? "未知错误");
          break;
      }
      //需要更多信息的错误码
      if (_detailedErrorCodes.contains(componentId)) {
        try {
          double ultrasonic = await _sampleController.getUltrasonic1();
          double armPositionX = await _sampleController.getArmPositionXValue();
          double armPositionY = await _sampleController.getArmPositionYValue();
          ret.write(" 超声波值: $ultrasonic X轴: $armPositionX Y轴: $armPositionY");
        } catch (e) {
          ret.write(" 获取详细信息时发生错误: $e");
        }
      }
      ret.write(";");
      return ret.toString();
    }

    // 订阅错误事件
    _events.add(deviceService.eventBus.on<ErrorEvent>().listen((event) async {
      errList = event.errors; // 更新错误列表
      // 获取新出现的错误（未处理过的）
      List<SetComponentError> newErrList = errList
          .where((e) => !_previousErrorHashes.contains(e.content.hashCode))
          .toList();
      if (newErrList.isEmpty) return;
      /***************************************************************
       *  content 第一个字符为模组信息，
       * 后面若为特殊错误码会有详细信息关键数字，接着为对应错误码错误内容
       * **************************************************************/
      //获取哪个模组错误
      // int containerId = int.parse(newErrList[0].content.substring(0, 1));
      int containerId = 0;
      List<String> errorStrings = await Future.wait(
        newErrList.map((error) async {
          try {
            return await parseErrorStr(error);
          } catch (e) {
            return "解析错误信息是发生异常: $e;";
          }
        }),
      );
      String errStr = errorStrings.join();
      // 记录错误日志（通道0和1）
      deviceService.addErrorLog(containerId, "报错信息:$errStr");
      // 更新已处理错误的哈希值
      _previousErrorHashes = errList.map((e) => e.content.hashCode).toSet();
      update(); // 错误状态变化时更新UI
    }));
    super.onInit();
  }

  @override
  void onClose() {
    // 清理资源
    _timer.cancel(); // 取消定时器
    for (var i in _events) {
      i.cancel(); // 取消所有事件订阅
    }
    super.onClose();
  }

  /// 连接串口
  /// [index] 串口列表中的索引
  /// 返回连接是否成功
  Future<bool> connectSerialPort(int index) async {
    // 索引有效性检查
    if (index > serialPortList.length - 1) return false;

    // 记录操作日志
    deviceService.addOperationLog(0, "执行打开串口操作");
    deviceService.addOperationLog(1, "执行打开串口操作");

    // 通过设备服务启动总线连接
    final result =
        await deviceService.startBus(serialPortList[index].keys.first);

    // 显示连接结果提示
    if (!result) {
      showHint("打开串口失败", HintType.DANGER);
    } else {
      showHint("打开串口成功", HintType.SUCCESS);
    }

    // 记录系统日志
    deviceService.addSystemLog(0, "打开串口:${result ? "成功" : "失败"}");
    deviceService.addSystemLog(1, "打开串口:${result ? "成功" : "失败"}");

    return result;
  }

  /// 断开串口连接
  void disconnectSerialPort() async {
    deviceService.closeBus(); // 通过设备服务关闭总线连接
  }
}
